﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DamageCalculator.Classes
{
    public class Character : IComparable
    {
        String mName;
        List<Encounter> mEncounters;
        CharType mCharacterType;
        bool iswatched;
        List<Character> mPets;
        bool misPet;

        #region display items
        double mDmgDone;
        double mDPS;
        double mAvgDmg;
        double mDmgTaken;
        double mDTPS;
        double mHealed;
        double mHPS;
        double mHealsTaken;
        double mHTPS;
        double mAvgHeal;
        double mXPHour;
        #endregion

        public enum CharType
        {
            None,
            Player,
            NPC,
            Pet,
        }

        public Character(String pName)
        {
            this.mName = pName;
            this.mEncounters = new List<Encounter>();
            this.mCharacterType = CharType.None;
            this.mPets = new List<Character>();
        }

        public Character(String pName, Encounter pFirstEncounter)
            :this(pName)
        {
            this.mEncounters.Add(new Encounter(pFirstEncounter.EncounterID, pFirstEncounter.StartTime));
        }

        public List<Character> Pets
        {
            get { return this.mPets; }
        }

        public bool isPet
        {
            get { return this.misPet; }
            set { this.misPet = value; }
        }

        public bool WatchChar
        {
            get { return this.iswatched; }
            set { this.iswatched = value; }
        }

        public String Name
        {
            get { return this.mName; }
        }

        public List<Encounter> Encounters
        {
            get { return this.mEncounters; }
        }

        public CharType CharacterType
        {
            get { return this.mCharacterType; }
            set { this.mCharacterType = value; }
        }

        public void Recalculate()
        {
            double totaldmg = 0;
            int totaldmgcount = 0;
            double totaldmgtaken = 0;
            int totaldmgtakencount = 0;
            double totalheals = 0;
            int totalhealscount = 0;
            double totalhealstaken = 0;
            int totalhealstakencount = 0;
            double totalXpGained = 0;

            int totalseconds = 0;
            try
            {
                foreach (Encounter E in this.mEncounters)
                {
                    List<Entry> getXPentry = null;
                    getXPentry = E.Entries.FindAll(
                        delegate(Entry e)
                        {
                            return e.EventType == ParsableLogEntry.EventTypes.GetXp;
                        }
                    );
                    foreach (Entry t in getXPentry)
                        totalXpGained += t.Amount;

                    List<Entry> givedmgentry = null;
                    givedmgentry = E.Entries.FindAll(
                        delegate(Entry e)
                        {
                            return e.EventType == ParsableLogEntry.EventTypes.GiveDamage || e.EventType == ParsableLogEntry.EventTypes.CriticalGiveDamage;
                        }
                    );

                    foreach (Character C in this.mPets)
                    {
                        Encounter TempPetEncounter = C.Encounters.Find(
                            delegate(Encounter pe)
                            {
                                return pe.EncounterID == E.EncounterID;
                            }
                        );

                        if (TempPetEncounter != null)
                        {
                            try
                            {
                                givedmgentry.AddRange(TempPetEncounter.Entries.FindAll(
                                    delegate(Entry pe)
                                    {
                                        return pe.EventType == ParsableLogEntry.EventTypes.GiveDamage || pe.EventType == ParsableLogEntry.EventTypes.CriticalGiveDamage;
                                    }
                                ));
                            }
                            catch { }
                        }
                    }

                    foreach (Entry t in givedmgentry)
                        totaldmg += t.Amount;

                    totaldmgcount += givedmgentry.Count;

                    List<Entry> getdmgentry = null;

                    getdmgentry = E.Entries.FindAll(
                        delegate(Entry e)
                        {
                            return e.EventType == ParsableLogEntry.EventTypes.GetDamage || e.EventType == ParsableLogEntry.EventTypes.CriticalGetDamage;
                        }
                    );

                    foreach (Entry t in getdmgentry)
                        totaldmgtaken += t.Amount;

                    totaldmgtakencount += givedmgentry.Count;

                    List<Entry> givehealsentry = null;

                    givehealsentry = E.Entries.FindAll(
                        delegate(Entry e)
                        {
                            return (e.EventType == ParsableLogEntry.EventTypes.GiveHeal || e.EventType == ParsableLogEntry.EventTypes.CriticalGiveHeal) && e.ActiveChar == this.Name;
                        }
                    );

                    foreach (Character C in this.mPets)
                    {
                        Encounter TempPetEncounter = C.Encounters.Find(
                            delegate(Encounter pe)
                            {
                                return pe.EncounterID == E.EncounterID;
                            }
                        );

                        if (TempPetEncounter != null)
                        {
                            try
                            {
                                givehealsentry.AddRange(TempPetEncounter.Entries.FindAll(
                                    delegate(Entry pe)
                                    {
                                        return (pe.EventType == ParsableLogEntry.EventTypes.GiveHeal || pe.EventType == ParsableLogEntry.EventTypes.CriticalGiveHeal) && pe.ActiveChar == C.Name;
                                    }
                                ));
                            }
                            catch { }
                        }
                    }

                    foreach (Entry t in givehealsentry)
                        totalheals += t.Amount;

                    totalhealscount += givehealsentry.Count;

                    List<Entry> gethealsentry = null;

                    gethealsentry = E.Entries.FindAll(
                        delegate(Entry e)
                        {
                            return (e.EventType == ParsableLogEntry.EventTypes.GetHeal || e.EventType == ParsableLogEntry.EventTypes.CriticalGetHeal) && e.ActiveChar == this.Name;
                        }
                    );

                    foreach (Entry t in gethealsentry)
                        totalhealstaken += t.Amount;

                    totalhealstakencount += gethealsentry.Count;

                    totalseconds += E.LengthInSeconds;
                }

                this.mDmgDone = totaldmg;
                this.mAvgDmg = totaldmg / (double)totaldmgcount;
                this.mDPS = totaldmg / (double)totalseconds;

                this.mDmgTaken = totaldmgtaken;
                this.mDTPS = totaldmgtaken / (double)totalseconds;

                this.mHealed = totalheals;
                this.mAvgHeal = totalheals / (double)totalhealscount;
                this.mHPS = totalheals / (double)totalseconds;

                this.mHealsTaken = totalhealstaken;
                this.mHTPS = totalhealstaken / (double)totalseconds;

                this.mXPHour = (totalXpGained / (double)(DateTime.Now - this.Encounters[0].StartTime).TotalSeconds) * 60d * 60d;
            }
            catch
            {
                this.mDmgDone = 0;
                this.mAvgDmg = Double.NaN;
                this.mDPS = 0;

                this.mDmgTaken = 0;
                this.mDTPS = 0;

                this.mHealed = 0;
                this.mAvgHeal = double.NaN;
                this.mHPS = 0;

                this.mHealsTaken = 0;
                this.mHTPS = 0;

                this.mXPHour = 0;
            }
        }

        public void Recalculate(long EncounterID)
        {
            try
            {
                Encounter current = this.mEncounters.Find(
                    delegate(Encounter E)
                    {
                        return E.EncounterID == EncounterID;
                    }
                );
                if (current == null)
                {
                    this.mDmgDone = 0;
                    this.mAvgDmg = Double.NaN;
                    this.mDPS = 0;

                    this.mDmgTaken = 0;
                    this.mDTPS = 0;

                    this.mHealed = 0;
                    this.mAvgHeal = double.NaN;
                    this.mHPS = 0;

                    this.mHealsTaken = 0;
                    this.mHTPS = 0;

                    this.mXPHour = 0;
                }
                if (current != null)
                {

                    List<Entry> getXPentry = null;
                    getXPentry = current.Entries.FindAll(
                        delegate(Entry e)
                        {
                            return e.EventType == ParsableLogEntry.EventTypes.GetXp;
                        }
                    );

                    double xp = 0;

                    foreach (Entry t in getXPentry)
                        xp += t.Amount;

                    this.mXPHour = (xp / (double)(DateTime.Now - current.StartTime).TotalSeconds) * 60d * 60d;

                    List<Entry> givedmgenty = null;

                    try
                    {
                        givedmgenty = current.Entries.FindAll(
                            delegate(Entry E)
                            {
                                return E.EventType == ParsableLogEntry.EventTypes.GiveDamage || E.EventType == ParsableLogEntry.EventTypes.CriticalGiveDamage;
                            }
                        );
                    }
                    catch { }

                    foreach (Character C in this.mPets)
                    {
                        Encounter TempPetEncounter = C.Encounters.Find(
                            delegate(Encounter pe)
                            {
                                return pe.EncounterID == current.EncounterID;
                            }
                        );

                        if (TempPetEncounter != null)
                        {
                            try
                            {
                                givedmgenty.AddRange(TempPetEncounter.Entries.FindAll(
                                    delegate(Entry pe)
                                    {
                                        return pe.EventType == ParsableLogEntry.EventTypes.GiveDamage || pe.EventType == ParsableLogEntry.EventTypes.CriticalGiveDamage;
                                    }
                                ));
                            }
                            catch { }
                        }
                    }

                    double totaldmg = 0;

                    if (givedmgenty != null)
                    {
                        foreach (Entry E in givedmgenty)
                        {
                            totaldmg += E.Amount;
                        }
                    }

                    this.mDmgDone = totaldmg;

                    if (current.EndTime != new DateTime())
                        this.mDPS = totaldmg / (current.EndTime - current.StartTime).TotalSeconds;
                    else
                        this.mDPS = totaldmg / (DateTime.Now - current.StartTime).TotalSeconds;

                    this.mAvgDmg = totaldmg / (double)givedmgenty.Count;

                    List<Entry> getDmgEntry = current.Entries.FindAll(
                        delegate(Entry E)
                        {
                            return E.EventType == ParsableLogEntry.EventTypes.GetDamage || E.EventType == ParsableLogEntry.EventTypes.CriticalGetDamage;
                        }
                    );

                    double totaldmgtaken = 0;
                    foreach (Entry E in getDmgEntry)
                        totaldmgtaken += E.Amount;

                    this.mDmgTaken = totaldmgtaken;
                    if (current.EndTime != new DateTime())
                        this.mDTPS = totaldmgtaken / (current.EndTime - current.StartTime).TotalSeconds;
                    else
                        this.mDTPS = totaldmgtaken / (DateTime.Now - current.StartTime).TotalSeconds;

                    //get healing given stats

                    List<Entry> giveHealsEntry = current.Entries.FindAll(
                        delegate(Entry E)
                        {
                            return (E.EventType == ParsableLogEntry.EventTypes.CriticalGiveHeal || E.EventType == ParsableLogEntry.EventTypes.GiveHeal) && E.ActiveChar == this.Name;
                        }
                    );

                    foreach (Character C in this.mPets)
                    {
                        Encounter TempPetEncounter = C.Encounters.Find(
                            delegate(Encounter pe)
                            {
                                return pe.EncounterID == current.EncounterID;
                            }
                        );

                        if (TempPetEncounter != null)
                        {
                            try
                            {
                                giveHealsEntry.AddRange(TempPetEncounter.Entries.FindAll(
                                    delegate(Entry pe)
                                    {
                                        return (pe.EventType == ParsableLogEntry.EventTypes.GiveHeal || pe.EventType == ParsableLogEntry.EventTypes.CriticalGiveHeal) && pe.ActiveChar == C.Name;
                                    }
                                ));
                            }
                            catch { }
                        }
                    }

                    double totalhealsgiven = 0;

                    foreach (Entry E in giveHealsEntry)
                        totalhealsgiven += E.Amount;

                    this.mHealed = totalhealsgiven;
                    if (current.EndTime != new DateTime())
                        this.mHPS = totalhealsgiven / (current.EndTime - current.StartTime).TotalSeconds;
                    else
                        this.mHPS = totalhealsgiven / (DateTime.Now - current.StartTime).TotalSeconds;

                    this.mAvgHeal = totalhealsgiven / (double)giveHealsEntry.Count;

                    //get healing taken stats

                    double totalhealstaken = 0;
                    List<Entry> gethealsentry = current.Entries.FindAll(
                        delegate(Entry E)
                        {
                            return (E.EventType == ParsableLogEntry.EventTypes.GetHeal || E.EventType == ParsableLogEntry.EventTypes.CriticalGetHeal);
                        }
                    );

                    foreach (Entry E in gethealsentry)
                        totalhealstaken += E.Amount;

                    this.mHealsTaken = totalhealstaken;
                    if (current.EndTime != new DateTime())
                        this.mHTPS = totalhealstaken / (current.EndTime - current.StartTime).TotalSeconds;
                    else
                        this.mHTPS = totalhealstaken / (DateTime.Now - current.StartTime).TotalSeconds;
                }
            }
            catch
            {
                this.mDmgDone = 0;
                this.mAvgDmg = Double.NaN;
                this.mDPS = 0;

                this.mDmgTaken = 0;
                this.mDTPS = 0;

                this.mHealed = 0;
                this.mAvgHeal = double.NaN;
                this.mHPS = 0;

                this.mHealsTaken = 0;
                this.mHTPS = 0;

                this.mXPHour = 0;
            }
        }

        public ListViewItem GenerateListViewItem()
        {
            ListViewItem temp = new ListViewItem(this.Name);
            temp.SubItems.Add(this.mDmgDone.ToString("0.00"));
            temp.SubItems.Add(this.mDPS.ToString("0.00"));
            temp.SubItems.Add(this.mAvgDmg.ToString("0.00"));
            temp.SubItems.Add(this.mDmgTaken.ToString("0.00"));
            temp.SubItems.Add(this.mDTPS.ToString("0.00"));
            temp.SubItems.Add(this.mHealed.ToString("0.00"));
            temp.SubItems.Add(this.mHPS.ToString("0.00"));
            temp.SubItems.Add(this.mHealsTaken.ToString("0.00"));
            temp.SubItems.Add(this.mHTPS.ToString("0.00"));
            temp.SubItems.Add(this.mAvgHeal.ToString("0.00"));
            temp.SubItems.Add(this.mXPHour.ToString("0.00"));
            temp.Tag = this;
            return temp;
        }

        public override string ToString()
        {
            return this.Name + " Dmg Done: " + this.mDmgDone.ToString("0.00") + " DPS: " + this.mDPS.ToString("0.00") + " Healing Done: " + this.mHealed.ToString("0.00") + " HPS: " + this.mHPS.ToString("0.00");
        }

        public int CompareTo(object obj)
        {
            return this.Name.CompareTo(((Character)obj).Name);
        }
    }
}
